#include "card.h"
#include "device.h"
#include "card_nxp520.h"
#include "card_crypto.h"

/* 调试打印接口 */
#define CARD_LOG(format, ...)     OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)
#define __CARD_LOG(format, ...)   //__OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)

/* 虚拟硬件接口 */
#define VHW_IRQ_CARD vPIN_I4

/* 天线环境值更新系数 */
#define ANT_UPDATE_FACTOR (3)

/* ADC卡片侦测阀值 */
#if defined(CARD_SIZE_BIG) //大卡片
#define ANT_THRESHOLD_RATIO (0.12) //TODO，待调试
#else
#define ANT_THRESHOLD_RATIO (0.12)
#endif

#define NFC_LPCD //17580 17622支持LPCD

__NVRAM static uint8_t card_wake_flag = 0;

/* 卡片工作模式 */
static CardMode_enum_t card_mode = CARD_MODE_VERIFY;

__EFRAM static FunctionalState card_func = ENABLE;



/**
  * @brief  处理验证卡片、添加卡片
  * @note   验证卡片是否合法
  *         
  * @param  type：卡片类型
  * @param  pID：卡片ID号
  * @param  len：ID号长度
  * 
  * @return SUCCESS/ERROR
  */
static ErrorStatus Card_ProcessVerifyOrAddCard(uint8_t type, uint8_t *pID, uint8_t len, uint8_t *err)
{
	if (card_mode == CARD_MODE_VERIFY) //验证卡片
	{
		/* 读ID成功：验证卡片是否合法  */
		if (CardCrypto_VerifyCard(pID, len, type, err) != ERROR)
		{
			CARD_LOG("verify success\r\n");
			return SUCCESS;
		}
		CARD_LOG("verify failed\r\n");
	}
	else if (card_mode == CARD_MODE_ADD) //添加卡片
	{
		/* 读ID成功：执行卡片添加流程  */
		if (CardCrypto_AddCard(pID, len, type) != ERROR)
		{
			CARD_LOG("add success\r\n");
			return SUCCESS;
		}
		CARD_LOG("add failed\r\n");
	}
	return ERROR;
}

#ifdef NFC_LPCD

#define  JREG_COMMAND         0x01
#define  JREG_VERSION         0x37    //Contains the product number and the version .

#define     CMD_SOFT_RESET    0x0F 

//=================扩展寄存器===========================================
#define JREG_EXT_REG_ENTRANCE 0x0F //ext register entrance
//============================================================================
#define JBIT_EXT_REG_WR_ADDR 0x40 //wrire address cycle
#define JBIT_EXT_REG_RD_ADDR 0x80 //read address cycle
#define JBIT_EXT_REG_WR_DATA 0xC0 //write data cycle
#define JBIT_EXT_REG_RD_DATA 0x00 //read data cycle


//================扩展寄存器二级地址===========================================
//========================0x24==============================================
#define   JREG_LPCDGMSEL               0x24
//============================================================================
#define   LPCD_ENB_AGC_AVDD            0x00
#define   LPCD_ENB_AGC_DVDD            0x10

#define   LPCD_RXCHANGE_JUDGE_MODE_0   0x00
#define   LPCD_RXCHANGE_JUDGE_MODE_1   0x04

#define   LPCD_GM_SEL_0                0x00
#define   LPCD_GM_SEL_1                0x01
#define   LPCD_GM_SEL_2                0x02
#define   LPCD_GM_SEL_3                0x03
//============================================================================
//========================0x25================================================
#define   JREG_LPCDSARADC1             0x25
//============================================================================
#define   SARADC_SOC_CFG_4             0x00
#define   SARADC_SOC_CFG_8             0x01
#define   SARADC_SOC_CFG_16            0x02
#define   SARADC_SOC_CFG_24            0x03
//============================================================================
//============================================================================
#define   JREG_LPCDDELTA_HI            0x26
//============================================================================
//============================================================================
#define   JREG_LPCDDELTA_LO            0x27
//============================================================================
//============================================================================
#define   JREG_LPCDICURR_HI            0x28
//============================================================================
//============================================================================
#define   JREG_LPCDICURR_LO            0x29
//============================================================================
//============================================================================
#define   JREG_LPCDQCURR_HI            0x2A
//============================================================================
//============================================================================
#define   JREG_LPCDQCURR_LO            0x2B
//============================================================================
//============================================================================
#define   JREG_LPCDILAST_HI            0x2C
//============================================================================
//============================================================================
#define   JREG_LPCDILAST_LO            0x2D
//============================================================================
//============================================================================
#define   JREG_LPCDQLAST_HI            0x2E
//============================================================================

//============================================================================
#define   JREG_LPCDQLAST_LO            0x2F
//============================================================================
//========================0x33================================================
#define   JREG_LPCDSLEEPTIMER          0x33
//============================================================================
//========================0x35================================================
#define   JREG_LPCDTHRESH_L            0x35
//============================================================================
//============================================================================
#define   JREG_LPCDREQATIMER           0x37
//============================================================================
#define   LPCD_IRQMISSWUP_ENABLE       0x20
#define   LPCD_IRQMISSWUP_DISABLE      0x00

#define   LPCD_REQA_TIME_80us          0x00
#define   LPCD_REQA_TIME_100us         0x01
#define   LPCD_REQA_TIME_120us         0x02
#define   LPCD_REQA_TIME_150us         0x03
#define   LPCD_REQA_TIME_200us         0x04
#define   LPCD_REQA_TIME_250us         0x05
#define   LPCD_REQA_TIME_300us         0x06
#define   LPCD_REQA_TIME_400us         0x07
#define   LPCD_REQA_TIME_500us         0x08
#define   LPCD_REQA_TIME_600us         0x09
#define   LPCD_REQA_TIME_800us         0x0A
#define   LPCD_REQA_TIME_1ms           0x0B
#define   LPCD_REQA_TIME_1ms2          0x0C
#define   LPCD_REQA_TIME_1ms6          0x0D
#define   LPCD_REQA_TIME_2ms           0x0E
#define   LPCD_REQA_TIME_2ms5          0x0F
#define   LPCD_REQA_TIME_3ms           0x10
#define   LPCD_REQA_TIME_3ms5          0x11
#define   LPCD_REQA_TIME_4ms           0x12
#define   LPCD_REQA_TIME_5ms           0x13
#define   LPCD_REQA_TIME_7ms           0x14

//============================================================================
//========================0x3A================================================
#define   JREG_LPCDCTRLMODE            0x3A
//============================================================================
#define   RF_DET_ENABLE                0x40
#define   RF_DET_DISABLE               0x00

#define   RF_DET_SEN_135mV             0x00
#define   RF_DET_SEN_180mV             0x08
#define   RF_DET_SEN_240mV             0x10
#define   RF_DET_SEN_300mV             0x18

#define   LPCD_DISABLE                 0x00
#define   LPCD_ENABLE                  0x02
//============================================================================
//========================0x39================================================
#define   JREG_LPCDDETECTMODE          0x39
//============================================================================
#define   LPCD_TXSCALE_0               0x00                  //1/8 of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_1               0x08                  //1/4 of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_2               0x10                  //1/2 of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_3               0x18                  //3/4 of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_4               0x20                  //equal to of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_5               0x28                  //twice of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_6               0x30                  //3 times of the TX power configured by CWGSP/CWGSNON
#define   LPCD_TXSCALE_7               0x31                  //4 times of the TX power configured by CWGSP/CWGSNON

#define   LPCD_RX_CHANGE_MODE          0x00
#define   LPCD_REQA_MODE               0x01
#define   LPCD_COMBINE_MODE            0x02

//============================================================================
//============================================================================
#define   JREG_LPCDIRQ                 0x3B
//============================================================================
//========================0x3C================================================
#define   JREG_LPCDRFTIMER             0x3C
//============================================================================
#define   LPCD_IRQINV_ENABLE           0x20
#define   LPCD_IRQINV_DISABLE          0x00

#define   LPCD_IRQ_PUSHPULL            0x10
#define   LPCD_IRQ_OD                  0x00

#define   LPCD_RFTIME_5us              0x00
#define   LPCD_RFTIME_10us             0x01
#define   LPCD_RFTIME_15us             0x02
#define   LPCD_RFTIME_20us             0x03
#define   LPCD_RFTIME_25us             0x04                  //default
#define   LPCD_RFTIME_30us             0x05
#define   LPCD_RFTIME_35us             0x06
#define   LPCD_RFTIME_40us             0x07
#define   LPCD_RFTIME_50us             0x08
#define   LPCD_RFTIME_60us             0x09
#define   LPCD_RFTIME_70us             0x0A
#define   LPCD_RFTIME_80us             0x0B
#define   LPCD_RFTIME_100us            0x0C
#define   LPCD_RFTIME_120us            0x0D
#define   LPCD_RFTIME_150us            0x0E
#define   LPCD_RFTIME_200us            0x0F
//============================================================================
//============================================================================
#define   JREG_LPCDTXCTRL2             0x3E
//============================================================================
//============================================================================
#define   JREG_LPCDTXCTRL3             0x3F
//============================================================================
#define   LPCD_FLAG_TOUT_ENABLE        0x20                  //TOUT Pad, set while LPCD DETECT, clear while LPCD SLEEP/SETUP(LPCD_TXEN_FLAG_INV = 0);
#define   LPCD_FLAG_TOUT_DISABLE       0x00                  //disable TOUT Pad as the LPCD DETECT flag.

#define   LPCD_FLAG_D3_ENABLE          0x10                  //D3 Pad, set while LPCD DETECT, clear while LPCD SLEEP/SETUP(LPCD_TXEN_FLAG_INV = 0);
#define   LPCD_FLAG_D3_DISABLE         0x00                  //disable D3 Pad as the LPCD DETECT flag.
//============================================================================


#define LPCD_CWP 63 //LPCD PMOS输出驱动 0~63
#define LPCD_CWN 15 //LPCD NMOS输出驱动 0~15

#define	LPCD_THRSH_H         0x00		//阈值高位
#define	LPCD_THRSH_L         0x20		//阈值低位
#define	LPCD_SLEEPTIME       16 		//LPCD 唤醒间隔时间，每一档为32ms，休眠时间：(16+1)*32=544ms


//***********************************************
//函数名称：GetReg_Ext(unsigned char ExtRegAddr,unsigned char* ExtRegData)
//函数功能：读取扩展寄存器值
//入口参数：ExtRegAddr:扩展寄存器地址   ExtRegData:读取的值
//出口参数：unsigned char  TRUE：读取成功   FALSE:失败
//***********************************************
void GetReg_Ext(unsigned char ExtRegAddr,unsigned char* ExtRegData)
{
	Nxp520_Write_Reg(JREG_EXT_REG_ENTRANCE,JBIT_EXT_REG_RD_ADDR + ExtRegAddr);
	* ExtRegData = Nxp520_Read_Reg(JREG_EXT_REG_ENTRANCE);
	//CARD_LOG("read reg %02x",*ExtRegData);
	return;	
}

//***********************************************
//函数名称：SetReg_Ext(unsigned char ExtRegAddr,unsigned char* ExtRegData)
//函数功能：写扩展寄存器
//入口参数：ExtRegAddr:扩展寄存器地址   ExtRegData:要写入的值
//出口参数：unsigned char  TRUE：写成功   FALSE:写失败
//***********************************************
void SetReg_Ext(unsigned char ExtRegAddr, unsigned char ExtRegData)
{
	Nxp520_Write_Reg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_WR_ADDR + ExtRegAddr);
	Nxp520_Write_Reg(JREG_EXT_REG_ENTRANCE, JBIT_EXT_REG_WR_DATA + ExtRegData);
	return;
}



//***********************************************
//函数名称：Lpcd_Get_ADC_Value()
//函数功能：Lpcd_Get_ADC_Value读取LPCD的ADC数据
//入口参数：
//出口参数：
//***********************************************
void Lpcd_Get_ADC_Value(void)
{
	unsigned char reg,reg1;
	unsigned char Current1,Current2;
	{
		GetReg_Ext(JREG_LPCDICURR_HI, &reg);
		GetReg_Ext(JREG_LPCDICURR_LO, &reg1);
		Current1 = (reg<<6) + reg1;
		Current2 = ((reg<<6)>>8);
		CARD_LOG("-> LPCD I Current is: %02x%02x",Current2,Current1);
		
		GetReg_Ext(JREG_LPCDQCURR_HI, &reg);
		GetReg_Ext(JREG_LPCDQCURR_LO, &reg1);
		Current1 = (reg<<6) + reg1;
		Current2 = ((reg<<6)>>8);
		CARD_LOG("-> LPCD Q Current is: %02x%02x",Current2,Current1);
		
		GetReg_Ext(JREG_LPCDILAST_HI, &reg);
		GetReg_Ext(JREG_LPCDILAST_LO, &reg1);
		Current1 = (reg<<6) + reg1;
		Current2 = ((reg<<6)>>8);
		CARD_LOG("-> LPCD I Last is: %02x%02x",Current2,Current1);
		
		GetReg_Ext(JREG_LPCDQLAST_HI, &reg);
		GetReg_Ext(JREG_LPCDQLAST_LO, &reg1);
		Current1 = (reg<<6) + reg1;
		Current2 = ((reg<<6)>>8);
		CARD_LOG("-> LPCD Q Last is: %02x%02x",Current2,Current1);
		
		GetReg_Ext(JREG_LPCDDELTA_HI, &reg);
		GetReg_Ext(JREG_LPCDDELTA_LO, &reg1);
		Current1 = (reg<<6) + reg1;
		Current2 = ((reg<<6)>>8);
		CARD_LOG("-> LPCD Delta is: %02x%02x",Current2,Current1);
	}	
	return;	
}

unsigned char FM17622_SoftReset(void)
{	
	unsigned char reg_data;
	Nxp520_Write_Reg(JREG_COMMAND,CMD_SOFT_RESET);
	Device_DelayMs(2);//FM17622芯片复位需要2ms
	reg_data = Nxp520_Read_Reg(JREG_COMMAND);
	if(reg_data == 0x20)
		return SUCCESS;
	else
		return ERROR;
}

//***********************************************
//函数名称：Lpcd_Init_Register()
//函数功能：LPCD寄存器初始化配置
//入口参数：
//出口参数：
//***********************************************
static void Lpcd_Init_Register(void)
{
	uint8_t reset_data;
	//MF_NRST_H; //NPD=1
	Device_DelayUs(500);
	Device_DelayUs(500);
	//reset_data = FM17622_SoftReset();
	//if(reset_data == SUCCESS)//确认芯片版本
	{
		//CARD_LOG("card softreset success \r\n");
		SetReg_Ext(JREG_LPCDGMSEL, LPCD_ENB_AGC_DVDD|LPCD_RXCHANGE_JUDGE_MODE_1|LPCD_GM_SEL_0);
		SetReg_Ext(JREG_LPCDSARADC1, 0x38|SARADC_SOC_CFG_16);
		SetReg_Ext(JREG_LPCDCTRLMODE, RF_DET_DISABLE|RF_DET_SEN_135mV|LPCD_ENABLE);//

		SetReg_Ext(JREG_LPCDREQATIMER,LPCD_IRQMISSWUP_DISABLE|LPCD_REQA_TIME_1ms);
		SetReg_Ext(JREG_LPCDDETECTMODE, LPCD_TXSCALE_4|LPCD_COMBINE_MODE);

		//SetReg_Ext(JREG_LPCDDETECTMODE, LPCD_TXSCALE_4|LPCD_RX_CHANGE_MODE);
		SetReg_Ext(JREG_LPCDSLEEPTIMER, LPCD_SLEEPTIME);
		SetReg_Ext(JREG_LPCDRFTIMER, LPCD_IRQINV_ENABLE|LPCD_IRQ_PUSHPULL|LPCD_RFTIME_10us);//探测时间配置使用10us有助于降低功耗
		SetReg_Ext(JREG_LPCDTHRESH_L, LPCD_THRSH_L);
		SetReg_Ext(JREG_LPCDTXCTRL2, LPCD_CWP);
		SetReg_Ext(JREG_LPCDTXCTRL3, LPCD_FLAG_TOUT_DISABLE|LPCD_FLAG_D3_DISABLE|LPCD_CWN);
	}
	//else
	{
		//CARD_LOG("card softreset error\r\n");
	}

	

	MF_NRST_L;
}


#endif


/**
  * @brief  读取卡片ID 
  * @note   
  *         
  * @param  pID：id缓存区，必须大于10byte
  * @param  crypto: 加密验证选择
  * @param  para：0（正常中断触发读卡），1（强制读卡）
  * @return 无卡返回0，非法卡返回1，正常返回卡号长度（4/7/10）
  */
static uint8_t Card_ReadCardId(uint8_t *pID, uint8_t crypto, uint8_t para)
{
	if (card_func == DISABLE) //无刷卡功能
	{
		return 0;
	}
	uint8_t len = 0;
	uint8_t cardType;
	uint8_t reg;

	// Device_EnterCritical();
	
	MF_NRST_H;
	Device_Enable(VHW_SPI_CARD);

	GetReg_Ext(JREG_LPCDIRQ, &reg);//读取LPCD中断标志，LPCD中断需要判断LPCD IRQ RXCHANGE(0x04)是否置位
	SetReg_Ext(JREG_LPCDIRQ, reg);//CLEAR LPCD IRQ
	
	if((reg & 0x04) || para)
	{	
		Device_Write(vCAP_SENSE0, NULL, 0, 0);//关闭触摸
		Lpcd_Get_ADC_Value();			//读adc寄存器值，调试时开启
		Nxp520_Reset();                                     
		len = CardCrypto_ReadCardId(pID, &cardType); //读卡类型和卡ID
		if (len != 0)
		{
			CARD_LOG("Read card id succeed\r\n");
			if (crypto != 0)
			{
				uint8_t err = 0;
				if (Card_ProcessVerifyOrAddCard(cardType, pID, len, &err) != SUCCESS) //加密信息验证或者添加卡片
				{
					len |= 0X80;								//非法卡、添加失败：将len的bit7设置为1
					len |= (err == CARD_ERR_NO_ADD) ? 0X40 : 0; //合法卡片但未添加
				}
			}
		}
		CARD_LOG("card len %d",len);
		
		Lpcd_Init_Register();
		
        Device_Write(vCAP_SENSE0, NULL, 0, 2);//开启触摸
		
	}
	MF_NRST_L;
	Device_Disable(VHW_SPI_CARD);
	// Device_ExitCritical();


	return len;
}

/**
  * @brief  读取卡片ID
  * @note   设计防重复读卡逻辑，将读取到的卡片ID发给订阅者
  * @param  para：0（正常中断触发读卡），1（强制读卡）
  */
static uint8_t Card_ReadID(uint8_t para)
{
	static uint8_t count = 0;
	static FlagStatus activeFlag = RESET;
	CardMsg_t msg;

	memset((uint8_t *)&msg, 0x00, sizeof(CardMsg_t));
	
#ifndef CARD_CRYPTO_DISABLE
	msg.cardLen = Card_ReadCardId(msg.cardId, 1, para);
#else
	msg.cardLen = Card_ReadCardId(msg.cardId, 0, para);
#endif
	if (msg.cardLen > 0)
	{
		CARD_LOG("Card len:%#X,  id:%02X %02X %02X %02X\r\n", msg.cardLen, msg.cardId[0], msg.cardId[1], msg.cardId[2], msg.cardId[3]);
		OSAL_MessagePublish(&msg, sizeof(CardMsg_t));

	}

	
	return msg.cardLen;
}

/**
 * @brief  卡片中断唤醒唤醒回调
 *
 * @param  
 * @return 非0表示可以唤醒
 * @note 这个函数，是OS里面的空闲TASK掉用的
 * 		休眠状态下用户触发动作，OS会执行这个handle，确认是否可以唤醒系统
 */
static int32_t Card_IrqWakeupHandle(uint32_t dev)
{
	uint8_t cardId[10] = {0};
	int32_t aa = (int32_t)Card_ReadCardId(cardId, 0, 0);
	if (aa)
	{
		card_wake_flag = 1;
	}
    return aa;
}


/**
 * @brief  卡片硬件中断回调
 *
 * @param  
 * @note 	这个函数是在硬件中断里面跑的，一般在这里创建个ISR事件就行，其他逻辑放到TASK里面的ISR事件去处理
 * 			这个IrqHandle应该要在SLEEP事件里面关掉，在START事件里面开启
 * 			如果休眠后没关闭，后续一但硬件触发中断，就会直接唤醒系统了；正常应该是中断触发，确认读到卡了，才能唤醒
 */
static void Card_IrqHandle(void *data, uint32_t len)
{
	CARD_LOG("Card irqhandle\r\n");
	OSAL_EventCreateFromISR(COMP_CARD);
}

/**
 * @brief  设置卡片模式
 *
 * @param  mode：模式
 * @return 
 */
static ErrorStatus Card_SetWorkMode(CardMode_enum_t mode)
{
	card_mode = mode;
	return SUCCESS;
}

/**
 * @brief  设置卡片功能开关
 *
 * @param  func：功能
 * @return 
 */
static ErrorStatus Card_SetFunction(FunctionalState status)
{
	card_func = status;
	return SUCCESS;
}

/**
  * @brief  卡片初始化
  *         
  * @param  
  *
  */
static void Card_Init(void)
{
	unsigned char reg_data;
	uint8_t reset_data;
	static uint8_t init_flag = 0;

	/* 读卡器接口初始化 */
	Nxp520_Portinit();
	Device_DelayUs( 100 );
	reg_data = Nxp520_Read_Reg(JREG_VERSION);
	if(reg_data == 0xA2)//确认芯片版本
	{
		CARD_LOG("IC Version = FM17622 or FM17610 \r\n");
		OSAL_MessagePublishErrorCode(ERRCODE_TYPE_NFC, 0);
	}
	else
	{
		CARD_LOG("card id not found %02x\r\n",reg_data);
		OSAL_MessagePublishErrorCode(ERRCODE_TYPE_NFC, 1);
	}

	if(!init_flag)
	{
		init_flag = 1;
		/* 注册中断回调 */
		CARD_LOG("irqhandle init \r\n");
		Device_RegisteredCB(VHW_IRQ_CARD, Card_IrqHandle);
		
	}
	Lpcd_Init_Register();
	Device_Disable(VHW_SPI_CARD);
}



/**
  * @brief  卡片任务函数
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Card_Task(uint32_t event)
{
	
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		CARD_LOG("Card task start\r\n");
		
		Card_Init();
		Device_ConfigCB(VHW_IRQ_CARD, ENABLE);
		if (card_wake_flag)
		{
			OSAL_EventCreateFromISR(COMP_CARD);
		}

		SYS_API(Card_SetWorkMode);
		SYS_API(Card_SetFunction);
		return (event ^ EVENT_SYS_START);
	}

	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
		Device_ConfigCB(VHW_IRQ_CARD, DISABLE);
		CARD_LOG("Card task sleep\r\n");
		return (event ^ EVENT_SYS_SLEEP);
	}

	/* 系统中断事件 */
	if (event & EVENT_SYS_ISR)
	{
		Device_ConfigCB(VHW_IRQ_CARD, DISABLE);
		if (card_wake_flag)
		{
			card_wake_flag = 0;
			Card_ReadID(1);
		}
		else
		{
			Card_ReadID(0);
		}
		Device_ConfigCB(VHW_IRQ_CARD, ENABLE);
		return (event ^ EVENT_SYS_ISR);
	}

	return 0;
}
COMPONENT_TASK_EXPORT(COMP_CARD, Card_Task, 16);
COMPONENT_WAKEUP_EXPORT(COMP_CARD, Card_IrqWakeupHandle, VHW_IRQ_CARD); 
